#pragma once
#include "HashTable.h"

template<class K, class V>
class KOfT_Map
{
    public:
    const K& operator()(const std::pair<K, V>& kv) const
    {
        return kv.first;
    }
};

template<class K, class V>
class unordered_map
{
public:
    typedef typename HashTable<K, std::pair<const K, V>, KOfT_Map<K,V>, HashFunc<K>>::Iterator iterator;
    typedef typename HashTable<K, std::pair<const K, V>, KOfT_Map<K,V>, HashFunc<K>>::ConstIterator const_iterator;

    iterator begin()
    {
        return _ht.Begin();
    }
    iterator end()
    {
        return _ht.End();
    }

    const_iterator begin() const
    {
        return _ht.Begin();
    }
    const_iterator end() const
    {
        return _ht.End();
    }

    std::pair<iterator, bool> insert(const std::pair<K, V>& kv)
    {
        return _ht.Insert(kv);
    }

    bool erase(const K& key)
    {
        return _ht.Erase(key);
    }

    iterator find(const K& key)
    {
        return _ht.Find(key);
    }

    V& operator[](const K& key)
    {
        std::pair<iterator, bool> ret = insert({ key, V() });
        return ret.first->second;
    }

    V& at(const K& key)
    {
        auto it = find(key);
        if (it == end())
        {
            throw std::out_of_range("Key not found");
        }
        return it->_data.second;
    }

    const V& at(const K& key) const
    {
        auto it = find(key);
        if (it == end())
        {
            throw std::out_of_range("Key not found");
        }
        return it->_data.second;
    }

private:
    HashTable<K, std::pair<const K, V>, KOfT_Map<K, V>, HashFunc<K>> _ht;
};
